package com.ocp.socket.config;

import com.ocp.socket.busi.device.service.IDeviceInfoService;
import com.ocp.socket.busi.userinfo.service.IUserInfoService;
import com.ocp.socket.server.mina.ByteArrayCodecFactory;
import com.ocp.socket.server.mina.ConnectAuthFilter;
import com.ocp.socket.server.mina.MinaLongConnServerHandler;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

/**
 * @Auther: zhangzh
 * @Date: 2019/1/24 15:18
 * @Description:
 * @Version: 1.0.0
 */
@Configuration
public class MinaConfig {

    private final static Logger log = LoggerFactory.getLogger(MinaConfig.class);

    @Value("${sktPort}")
    private int sktPort;

    @Bean
    public LoggingFilter loggingFilter() {
        return new LoggingFilter();
    }
    @Bean
    public IoHandler ioHandler() {
        return new MinaLongConnServerHandler();
    }
    @Bean
    public InetSocketAddress inetSocketAddress() {
        return new InetSocketAddress(sktPort);
    }

    @Bean
    public ByteArrayCodecFactory byteArrayCodecFactory() {
        return  new ByteArrayCodecFactory(Charset.forName("UTF-8"));
    }

    @Bean
    public ConnectAuthFilter connectAuthFilter(IUserInfoService userInfoService,
                                               IDeviceInfoService deviceInfoService) {
        return new ConnectAuthFilter(userInfoService, deviceInfoService);
    }


    @Bean("ioAcceptor")
    public IoAcceptor ioAcceptor(IUserInfoService userInfoService,
                                 IDeviceInfoService deviceInfoService) {
        NioSocketAcceptor acceptor=new NioSocketAcceptor();
        //首先加载第一个过滤器是解码器
        DefaultIoFilterChainBuilder chainBuilder = acceptor.getFilterChain();
        //日志拦截器
        chainBuilder.addFirst("logger", loggingFilter());
        //编解码器
        chainBuilder.addAfter("logger", "myCodec", new ProtocolCodecFilter(byteArrayCodecFactory()));
        //连接认证器
        chainBuilder.addAfter("myCodec", "authfilter", connectAuthFilter(userInfoService, deviceInfoService));
        acceptor.setHandler(ioHandler());

        acceptor.getSessionConfig().setReadBufferSize(2048);

        // 读写通道15秒内无操作进入空闲状态
        //acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 15);
        try{
            //加上该配置，避免重启时提示地址被占用
            acceptor.setReuseAddress(true);
            acceptor.bind(inetSocketAddress());
        } catch (BindException e) {
            log.error("端口使用中....请关掉相关程序并重新运行服务器！", e);
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("socket启动异常....",e);
        }
        log.info("服务器在端口:[{}]已经启动",sktPort);
        return acceptor;
    }

}
